package org.bulldog.playlist.program;

import org.bulldog.playlist.PlayListBuilder;
import org.bulldog.playlist.util.DateUtil;

import java.util.*;

/**
 * 日常播表生成器
 *
 * @author zhanghongbin
 * @version 1.1
 */
final class DailyPlayListBuilder implements PlayListBuilder<List<Program>, Program> {

    private List<Program> sportsList;

    private static final String END_TIME = "23:59:59";

    /**
     * @param sportsList 插播节目列表
     */
    public DailyPlayListBuilder(List<Program> sportsList) {
        this.sportsList = sportsList;
    }

    /**
     * @param dailyProgramList 参数为排序后的
     * @return
     */
    @Override
    public List<Program> build(List<Program> dailyProgramList) {
        List<Program> playList;
        String currentTime = DateUtil.now();
        //一天的终止时间
        String endDate = currentTime.split(" ")[0] + " " + END_TIME;
        //不存在插播节目
        if (this.sportsList.isEmpty()) {
            playList = this.buildDailyPlayList(currentTime, dailyProgramList, endDate);
            //如果不存在日常节目,需要增加默认节目
            if (playList.isEmpty()) {
                this.addDefaultPlayList(playList, DateUtil.now(), endDate);
            }
        } else {
            if (dailyProgramList.isEmpty()) {
                //如果没有日常节目，插播节目需要在其它时间段填入默认节目
                playList = this.buildDefaultDailyPlayListBySpots(currentTime, endDate);
            } else {
                //适用于3.0.1之前版本,3.0.1之后没有日常节目都是插播节目
                playList = this.buildDailyPlayListBySpots(currentTime, dailyProgramList, endDate);
            }
        }
        return playList;
    }

    /**
     * 根据插播节目生成日常默认节目
     *
     * @param currentTime 当前时间  yyyy-MM-dd HH:mm:ss
     * @param endDate     一天的终止时间  yyyy-MM-dd HH:mm:ss
     * @return
     */
    private List<Program> buildDefaultDailyPlayListBySpots(String currentTime, String endDate) {
        List<Program> playList = new ArrayList<>();
        for (int i = 0; i < this.sportsList.size(); i++) {
            Program program = this.sportsList.get(i);
            String sportStartTime = program.getStartTime();
            int n = DateUtil.compare(currentTime, sportStartTime);
            if (n == -1) {
                this.addDefaultPlayList(playList, currentTime, sportStartTime);
                currentTime = program.getEndTime();
            } else if (n > 0 && this.sportsList.size() - 1 != i) {    //不是循环最后一个
                currentTime = this.sportsList.get(i + 1).getStartTime();
                if (!program.getEndTime().equals(currentTime)) {
                    this.addDefaultPlayList(playList, program.getEndTime(), currentTime);
                }
            } else {
                currentTime = program.getEndTime();
            }
        }
        currentTime = this.sportsList.get(this.sportsList.size() - 1).getEndTime();
        //最后时间和23:59:59 不相等需要增加默认节目到23:59:59
        if (!currentTime.equals(endDate)) {
            this.addDefaultPlayList(playList, currentTime, endDate);
        }
        return playList;
    }

    /**
     * 根据插播节目生成日常节目
     *
     * @param currentTime      当前时间  yyyy-MM-dd HH:mm:ss
     * @param dailyProgramList 日常节目列表
     * @return
     */
    private List<Program> buildDailyPlayListBySpots(String currentTime, List<Program> dailyProgramList, String endDate) {
        List<Program> playList = new ArrayList<>();
        label1:
        while (true) {
            for (int i = 0; i < dailyProgramList.size(); i++) {
                Program program = dailyProgramList.get(i);
                //从插播播表里查询是否有在当前时间区间的插播节目
                Program tempProgram = new Program();
                tempProgram.setStartTime(currentTime);
                int index = this.sportsList.indexOf(tempProgram);
                if (index == -1) {
                    currentTime = this.addPlayList(playList, program, currentTime);
                    if (!this.sportsList.isEmpty() && !playList.isEmpty()) {
                        int n = DateUtil.minus(currentTime, this.sportsList.get(0).getStartTime());
                        //日常节目的结束时间和插播节目的开始时间相减为负数的时候执行
                        if (n < 0) {
                            Program lastProgram = playList.get(playList.size() - 1);
                            int duration = DateUtil.minus(lastProgram.getStartTime(), this.sportsList.get(0).getStartTime());
                            //如果开始时间和结束时间小于30秒
                            if (duration < DateUtil.MIN_PLAY_DURATION) {
                                //删除当前节目因为播放时长太短
                                playList.remove(playList.size() - 1);
                                //把最后一个节目的结束时间和播放时长进行调整
                                lastProgram = playList.get(playList.size() - 1);
                                lastProgram.setEndTime(this.sportsList.get(0).getStartTime());
                                lastProgram.setPlayDuration(DateUtil.minus(lastProgram.getStartTime(), lastProgram.getEndTime()));
                                i = i - 1; // 重置
                            } else {
                                lastProgram.setEndTime(this.sportsList.get(0).getStartTime());
                                lastProgram.setPlayDuration(duration);
                            }
                            currentTime = lastProgram.getEndTime();
                        }
                    }
                } else {
                    while (true) {
                        Program sportsProgram = this.sportsList.remove(index);
                        currentTime = sportsProgram.getEndTime();
                        tempProgram = new Program();
                        tempProgram.setStartTime(currentTime);
                        index = this.sportsList.indexOf(tempProgram);
                        if (index == -1) {
                            currentTime = this.addPlayList(playList, program, sportsProgram.getEndTime());
                            break;
                        }
                    }
                }
                if (this.isPlayListEndTime(currentTime, endDate, playList)) {
                    break label1;
                }
            }
        }
        return playList;
    }

    /**
     * 生成所有日常节目播表
     *
     * @param currentTime      当前时间
     * @param dailyProgramList 节目列表
     * @param endDate          一天的终止时间
     * @return
     */
    private List<Program> buildDailyPlayList(String currentTime, List<Program> dailyProgramList, String endDate) {
        List<Program> playList = new ArrayList<>();
        if (dailyProgramList.isEmpty()) return playList;
        label1:
        while (true) {
            for (Program program : dailyProgramList) {
                currentTime = this.addPlayList(playList, program, currentTime);
                if (this.isPlayListEndTime(currentTime, endDate, playList)) {
                    break label1;
                }
            }
        }
        return playList;
    }

    private boolean isPlayListEndTime(String currentTime, String endDate, List<Program> playList) {
        if (DateUtil.compare(currentTime, endDate) >= 0) {
            Program program = playList.get(playList.size() - 1);
            if (program.getStartTime().equals(endDate)){
                playList.remove(playList.size()-1);
            }else{
                program.setEndTime(endDate);
                int duration = DateUtil.minus(program.getStartTime(), endDate);
                program.setPlayDuration(duration);
            }
            return true;
        }
        return false;
    }

    private String addPlayList(List<Program> playList, Program program, String currentTime) {
        Program tempProgram = new Program(program.getId(), program.getName(), program.getUrl(), program.getDuration());
        tempProgram.setPlayDuration(program.getDuration());
        tempProgram.setStartTime(currentTime);
        tempProgram.setEndTime(DateUtil.add(currentTime, program.getDuration()));
        tempProgram.getParams().putAll(program.getParams());
        playList.add(tempProgram);
        return tempProgram.getEndTime();
    }

    /**
     * 增加默认播放节目 默认播放节目id 用 -1 表示
     *
     * @param playList
     * @param startTime
     * @param endTime
     */
    private void addDefaultPlayList(List<Program> playList, String startTime, String endTime) {
        int n = DateUtil.minus(startTime, endTime);
        Program program = new Program("-1", "", "", n);
        program.setStartTime(startTime);
        program.setEndTime(endTime);
        program.setDuration(n);
        playList.add(program);
    }
}
